#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "profiles.h"
#include "version.h"
#include "audiocontrol.h"

#include <QSound>
#include <QTimer>
#include <QMessageBox>
#include <QSettings>
#include <QDir>
#include <QCloseEvent>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    n_timer = new QTimer(this);
    p_timer = new QTimer(this);
    a_timer = new QTimer(this);
    p_timer->setSingleShot(true);
    a_timer->setSingleShot(true);


    paused = false;
    stoped = true;
    profiles = 0;

    m_audioInput = 0;

    ui->setupUi(this);
    ui->total_lcdNumber->display(0);

    ui->audio_groupBox->hide();

    connect(n_timer, SIGNAL(timeout()), this, SLOT(increase()));
    connect(p_timer, SIGNAL(timeout()), n_timer, SLOT(start()));
    connect(a_timer, SIGNAL(timeout()), this, SLOT(start()));
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(pause()));
    connect(ui->actionReset, SIGNAL(triggered()), this, SLOT(reset()));
    connect(ui->actionReset_All, SIGNAL(triggered()), this, SLOT(resetAll()));
    connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(about()));
    connect(ui->actionContent, SIGNAL(triggered()), this, SLOT(helpContent()));
    connect(ui->actionManage, SIGNAL(triggered()), this, SLOT(manageProfiles()));
    //audio control
    connect(ui->device_comboBox, SIGNAL(activated(int)), this, SLOT(deviceChanged(int)));
    connect(ui->audio_pushButton, SIGNAL(toggled(bool)), this, SLOT(toggleAudio(bool)));

    this->loadSettings();
    this->loadAudioDevices();
    this->initializeAudio();
    this->generateProfiles();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::stop()
{
    if(qApp->property("endbeep").toBool()) qApp->beep();
    ui->pushButton->setText(tr("Start"));
    paused = false;
    stoped = true;
    a_timer->stop();
    n_timer->stop();
    p_timer->stop();
}

void MainWindow::start()
{
    if(qApp->property("startbeep").toBool()) qApp->beep();
    paused = false;
    stoped = false;
    ui->pushButton->setText(tr("Stop"));
    if(!ui->total_lcdTimer->timer->isActive())
        ui->total_lcdTimer->timer->start(1000);
    ui->number_lcdNumber->display(0);
    ui->cycle_lcdNumber->display(0);
    n_timer->setInterval(qApp->property("frequency").toInt());
    n_timer->start();
    if(a_timer->isActive()) a_timer->stop();
}

void MainWindow::reset()
{
    ui->number_lcdNumber->display(0);
    ui->cycle_lcdNumber->display(0);
}

void MainWindow::resetAll()
{
    this->stop();
    ui->total_lcdNumber->display(0);
    ui->number_lcdNumber->display(0);
    ui->cycle_lcdNumber->display(0);
    ui->total_lcdTimer->resetDisplay();
    ui->total_lcdTimer->stop();
}

void MainWindow::increase()
{
    if(ui->number_lcdNumber->intValue() >= qApp->property("number").toInt()){
        ui->number_lcdNumber->display(
                    (ui->audio_pushButton->isChecked() ? 0 : -1)
                    );
    }    
    ui->number_lcdNumber->display(ui->number_lcdNumber->intValue()+1);
    if(ui->number_lcdNumber->intValue()) ui->total_lcdNumber->display(ui->total_lcdNumber->intValue()+1);
    if(ui->number_lcdNumber->intValue() >= qApp->property("number").toInt()){
        ui->cycle_lcdNumber->display(ui->cycle_lcdNumber->intValue()+1);
        n_timer->stop();
        if(ui->cycle_lcdNumber->intValue()>=qApp->property("cycle").toInt()){//end
            this->stop();            
            loadNextProfile();
        }
        else{//pause
            if(!ui->audio_pushButton->isChecked())
                p_timer->start(qApp->property("pause").toInt());
        }
    }
    status();
}


void MainWindow::loadSettings(const QString& profile)
{
    QDir appdir = QDir::home();
    QSettings settings(appdir.filePath("Breath.ini"), QSettings::IniFormat);
    settings.beginGroup("Profiles");
    settings.beginGroup(profile);
    qApp->setProperty("number", settings.value("Numbers", 8).toInt());
    qApp->setProperty("cycle", settings.value("Cycles", 12).toInt());
    qApp->setProperty("frequency", settings.value("Frequency", 800).toInt());
    qApp->setProperty("pause", settings.value("Pause", 3000).toInt());
    settings.endGroup();
    settings.endGroup();
    settings.beginGroup("Program");
    qApp->setProperty("autostart", settings.value("AutoStart", false).toBool());
    qApp->setProperty("startbeep", settings.value("StartBeep", false).toBool());
    qApp->setProperty("endbeep", settings.value("EndBeep", false).toBool());
    qApp->setProperty("autostartseconds", settings.value("AutoStartSeconds", 10).toInt());
    settings.endGroup();

    qApp->setProperty("currentprofile", profile);

    ui->profile_label->setText(tr("Current profile: %1 (%2x%3)")
                               .arg(profile)
                               .arg(qApp->property("number").toInt())
                               .arg(qApp->property("cycle").toInt())
                               );
}

void MainWindow::about()
{
    QString msg(tr("Version: %1\nAuthor: Venelin Georgiev\nPleven, Bulgaria\nE-mail: veni_georgiev@mail.bg")
                .arg(_STR_PRODUCT_VERSION)
                );
    QMessageBox::about( this, tr("About Breath"), msg) ;
}

void MainWindow::helpContent()
{
    QString msg =
                "<ul>Breathing exercises Strelnikova, a unique method of health,"
                "created decades ago and has already healed many thousands of sick people ..."
                "This method will help you to health problems such as:"

                                 "<li> rhinitis </li>"
                                 "<li> adenoids </li>"
                                 "<li> sinusitis </li>"
                                 "<li> bronihit </li>"
                                 "<li> bronchial asthma </li>"
                                 "<li> skin disorders (a diathesis, atopic dermatitis, psoriasis) </li>"
                                 "<li> neurosis </li>"
                                 "<li> neuritis </li>"
                                 "<li> depression </li>"
                                 "<li> diseases of the cardiovascular system </li>"
                                 "<li> headaches </li>"
                                 "<li> epilepsy </li>"
                                 "<li> stroke </li>"
                                 "<li> hypertension, hypotension, somatoform autonomic dysfunction </ li>"
                                 "<li> stuttering </li>"
                                 "<li> osteochondrosis, scoliosis </li>"
                                 "<li> head injuries and spinal cord </li>"
                                 "<li> sexual disorders </li>"
                                 "<li> overweight </li>"
                                 "<li> smoking </li>"
                                 "</ul>"
                ;
    msg.append("<ul>Internet resources (Russian):");
    msg.append("<li><a href=\"http://shchetinin.com/\">http://shchetinin.com<a/></li>");
    msg.append("<li><a href=\"http://zdorovja.com.ua/content/view/295/73/\">http://zdorovja.com.ua<a/></li>");
    msg.append("<li><a href=\"http://voviyes.ru/gimnastika/dyhatelnaia-gimnastika\">http://voviyes.ru<a/></li>");
    msg.append("</ul>");
    msg.append("<ul>Video (YouTube):");
    msg.append("<li><a href=\"http://www.youtube.com/watch?v=hMulXYKF4hc&feature=related\">Ladoshki<a/></li>");
    msg.append("<li><a href=\"http://www.youtube.com/watch?v=J0sLxhQC8zM&feature=related\">Pogonchiki<a/></li>");
    msg.append("<li><a href=\"http://www.youtube.com/watch?v=-HzcsRWyaYQ&feature=relatedZ\">Nasos<a/></li>");
    msg.append("<li><a href=\"http://www.youtube.com/watch?v=wYo8S5UP63A&feature=related\">Koshcka<a/></li>");
    msg.append("<li><a href=\"http://www.youtube.com/watch?v=8OBvkk9x1oE&feature=mfu_in_order&list=UL\">Obnimi plechi<a/></li>");
    msg.append("<li><a href=\"http://www.youtube.com/watch?v=5vdnfaPGfwQ&feature=related\">Bolshoi mayatnik<a/></li>");
    msg.append("<li><a href=\"http://www.youtube.com/watch?v=qNSWJ2LGsYc&feature=related\">Povoroti<a/></li>");
    msg.append("<li><a href=\"http://www.youtube.com/watch?v=Fx8LiqgIUSk&feature=related\">Ushki<a/></li>");
    msg.append("<li><a href=\"http://www.youtube.com/watch?v=2mvFRt4MJ5U&feature=related\">Malenkii mayatnik<a/></li>");
    msg.append("<li><a href=\"http://www.youtube.com/watch?v=YmFAErlEVIM&feature=related\">Perekatui<a/></li>");
    msg.append("<li><a href=\"http://www.youtube.com/watch?v=nmsoaXfqbEw&feature=related\">Shagi<a/></li>");
    msg.append("</ul>");



    QMessageBox* box = new QMessageBox(this);
    box->setTextFormat(Qt::RichText);
    box->setWindowTitle("Breathing exercises Strelnikova");
    box->setText(msg);
    box->exec();

    delete(box);
}

void MainWindow::pause()
{
    if(qApp->property("endbeep").toBool()) qApp->beep();
    if(n_timer->isActive() || p_timer->isActive()){
        ui->pushButton->setText(tr("Start"));
        n_timer->stop();
        p_timer->stop();
        paused = true;
    }
    else{
        if(!paused) this->start();
        else{
           n_timer->setInterval(qApp->property("frequency").toInt());
           n_timer->start();
           ui->pushButton->setText(tr("Stop"));
        }
    }
    status();
}

void MainWindow::generateProfiles()
{
    if(profiles){
        for (int i = 0; i < profiles->actions().size(); ++i) {
             ui->menuProfiles->removeAction(profiles->actions().at(i));
         }
        delete profiles;
    }
    profiles = new QActionGroup(ui->menuProfiles);

    QAction* defaultProfile = new QAction("Default", profiles);
    defaultProfile->setData("Default");
    defaultProfile->setCheckable(true);
    defaultProfile->setChecked(false);
    connect(defaultProfile, SIGNAL(triggered()), this, SLOT(loadProfile()));
    profiles->addAction(defaultProfile);

    QDir appdir = QDir::home();
    QSettings settings(appdir.filePath("Breath.ini"), QSettings::IniFormat);
    settings.beginGroup("Profiles");
    QStringList list = settings.childGroups();
    for (int i = 0; i < list.size(); ++i){
        settings.beginGroup(list.at(i).toLocal8Bit().constData());
        QAction* action = new QAction(list.at(i).toLocal8Bit().constData(), profiles);
        action->setCheckable(true);
        action->setChecked(settings.value("Current", false).toBool());
        action->setData(list.at(i).toLocal8Bit().constData());
        connect(action, SIGNAL(triggered()), this, SLOT(loadProfile()));
        if(action->isChecked()){
            action->trigger();
        }
        profiles->addAction(defaultProfile);
        settings.endGroup();
    }
    settings.endGroup();

    ui->menuProfiles->addActions(profiles->actions());
}

void MainWindow::loadProfile()
{
    QAction *action = qobject_cast<QAction *>(sender());
    this->loadSettings(action->data().toString());
}

void MainWindow::manageProfiles()
{
    Profiles* profile = new Profiles(this);
    if(profile->exec() == QDialog::Accepted) generateProfiles();
}

void MainWindow::loadNextProfile()
{
    if(profiles){
        for (int i = 0; i < profiles->actions().size()-1; ++i) {
             if(profiles->actions().at(i)->isChecked()){
                 if(profiles->actions().at(i+1)){
                     profiles->actions().at(i+1)->trigger();
                     if(qApp->property("autostart").toBool() && !ui->audio_pushButton->isChecked()){
                         a_timer->start(qApp->property("autostartseconds").toInt()*1000);
                     }
                 }
                 else{
                     this->stop();
                 }
                 return;
             }
         }
    }
}

void MainWindow::status()
{
    ui->status_label->setText("");
    if(n_timer->isActive()){
        ui->status_label->setText(tr("In cycle ..."));
    }
    else if(p_timer->isActive()){
        ui->status_label->setText(tr("Paused ..."));
    }
    else if(a_timer->isActive()){
        ui->status_label->setText(tr("Waiting for autostart ..."));
    }
    else ui->status_label->setText(tr("Stopped"));
}

void MainWindow::setAudioLevel(qreal value)
{

}

void MainWindow::initializeAudio()
{
    m_pullMode = true;

    m_format.setFrequency(8000);
    m_format.setChannels(1);
    m_format.setSampleSize(16);
    m_format.setSampleType(QAudioFormat::SignedInt);
    m_format.setByteOrder(QAudioFormat::LittleEndian);
    m_format.setCodec("audio/pcm");

    QAudioDeviceInfo info(QAudioDeviceInfo::defaultInputDevice());
    if (!info.isFormatSupported(m_format)) {
        //qWarning() << "Default format not supported - trying to use nearest";
        m_format = info.nearestFormat(m_format);
    }

    m_audioControl  = new AudioControl(m_format, this);
    connect(m_audioControl, SIGNAL(update()), SLOT(audioControl()));

    createAudioInput();
}

void MainWindow::createAudioInput()
{
    m_audioInput = new QAudioInput(m_device, m_format, this);
    connect(m_audioInput, SIGNAL(notify()), SLOT(notified()));
    connect(m_audioInput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State)));

    //m_audioControl->start();
    //m_audioInput->start(m_audioControl);
}

void MainWindow::loadAudioDevices()
{
    QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
    for(int i = 0; i < devices.size(); ++i)
        ui->device_comboBox->addItem(devices.at(i).deviceName(), qVariantFromValue(devices.at(i)));

    QDir appdir = QDir::home();
    QSettings settings(appdir.filePath("Breath.ini"), QSettings::IniFormat);
    settings.beginGroup("Audio");
    ui->audio_spinBox->setValue(settings.value("Volume", 50).toInt());
    settings.endGroup();

    connect(ui->device_comboBox, SIGNAL(activated(int)), SLOT(deviceChanged(int)));
}

void MainWindow::deviceChanged(int index)
{
    m_audioControl->stop();
    m_audioInput->stop();
    m_audioInput->disconnect(this);
    delete m_audioInput;

    m_device = ui->device_comboBox->itemData(index).value<QAudioDeviceInfo>();
    qApp->setProperty("audio_device", index);
    createAudioInput();
}

void MainWindow::stateChanged(QAudio::State state)
{
    //qWarning() << "state = " << state;
}

void MainWindow::notified()
{
    /*qWarning() << "bytesReady = " << m_audioInput->bytesReady()
               << ", " << "elapsedUSecs = " <<m_audioInput->elapsedUSecs()
               << ", " << "processedUSecs = "<<m_audioInput->processedUSecs();
               */
}

void MainWindow::audioControl()
{
    qreal max = ui->audio_spinBox->value();
    max/=1000;
    if(ui->test_pushButton->isChecked()){
        if(m_audioControl->level() > 0.015){
            ui->audio_spinBox->setValue(int(m_audioControl->level()*1000));
        }
        return;
    }
    if(!n_timer->isActive()){
        if(m_audioControl->level() > max){
               if(stoped) start();
               else{
                   n_timer->setInterval(qApp->property("frequency").toInt());
                   n_timer->start();
                   ui->pushButton->setText(tr("Stop"));
               }
               this->increase();
        }
    }
}

void MainWindow::toggleAudio(bool toggle)
{
    this->deviceChanged(qApp->property("audio_device").toInt());
    ui->audio_groupBox->setVisible(toggle);
    if(toggle){
        m_audioControl->start();
        m_audioInput->start(m_audioControl);
    }
    else{
        m_audioInput->suspend();
        m_audioInput->reset();
    }
}

void MainWindow::saveSettings()
{
    QDir appdir = QDir::home();
    QSettings settings(appdir.filePath("Breath.ini"), QSettings::IniFormat);
    settings.beginGroup("Audio");
    settings.setValue("Volume", ui->audio_spinBox->value());
    settings.endGroup();
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    this->saveSettings();
    event->accept();
}



